/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package torrent;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Analyzer extends Function implements Runnable {

    // mang cac inetaddress, neu co nhieu peer, dung cho da luong
    static InetAddress inetlist[] = new InetAddress[5];
    static int curmaxInet = 0;
    static int port[] = new int[5];
    String stat;
    String filename;
    int chunk;
    InetAddress host;
    int firstport;
    int secondport;
    static Thread t;
    DatagramSocket ds = null;

    public Analyzer(String filename, String stat, int chunk, InetAddress host, int firstport, int secondport) {
        this.filename = filename;
        this.stat = stat;
        this.chunk = chunk;
        this.host = host;
        this.firstport = firstport;// port dung tao socket
        this.secondport = secondport;// port de gui
        t = new Thread(this);
    }

    public void run() {
        int flag = 0;
        int curInet = 0;
        try {
            ds = new DatagramSocket(firstport);
        } catch (SocketException ex) {
            Logger.getLogger(Analyzer.class.getName()).log(Level.SEVERE, null, ex);
        }

        if (stat.equals("send")) {

            send();
        }
        if (stat.equals("recv")) {
            receive(filename, chunk);// goi ham nhan chunk thu chunk
        }
        ds.close();
    }

    private void send() {
        int waitingsyn = 1;
        int waitingack = 1;// luu gia tri ack dung
        int synid = 1, ackid = 1;
        try {

            String x = filename + "." + chunk + ".chunk";
            FileInputStream fis = new FileInputStream("rsc//" + x);
            System.out.println(host.getHostAddress());
            byte[] sentBuf = null;
            sentBuf = new byte[1024];
            int len = 0;
            int k = 0;
            while ((len = fis.read(sentBuf, 8, 1016)) > 0) { // doc fis gan vao
                // sentbuf
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                int readbyte = 0;
                int oldsyn = synid;// oldsyn: syn ban dau
                while (oldsyn == synid) {
                    sentBuf = alterbuf(sentBuf, synid, ackid);
                    ByteBuffer syn = ByteBuffer.allocate(4); // doc bytebuff syn
                    // va ack
                    ByteBuffer ack = ByteBuffer.allocate(4);
                    syn.put(sentBuf, 0, 4); // ko nho ro, tu tu H comment
                    ack.put(sentBuf, 4, 4);
                    System.out.println(synid + " " + ackid+"for"+chunk);
                    DatagramPacket sentPacket = new DatagramPacket(sentBuf,
                            sentBuf.length, host, secondport);
                    ds.send(sentPacket);
                    k++;
                    int x1 = recieveapacket();// cho goi tin ack

                    if (x1 == waitingack) { // ack thoa dieu kien
                        waitingack = x1 + 1;
                        synid++;
                    } else {
                        System.out.println("Fell " + "syn boiy" + syn.getInt(0)
                                + "ack boiy" + ack.getInt(0));
                    }
                }
            }
            fis.close();
            return;
        } catch (Exception e) {
            e.printStackTrace();
            ds.close();
        }

    }

    private void receive(String filename, int numchunk) {
        int waitingsyn = 1;
        int waitingack = 1;
        int acknum = 0;
        boolean valid = false;
        Chunkstat = 0;
        try {
            byte[] receivedata = new byte[1024];
            int recieve = 0;
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int k = 0;
            while (recieve < 524288 - 1016) {

                DatagramPacket receivedPacket = new DatagramPacket(receivedata,
                        1024);
                ds.receive(receivedPacket);
                ByteBuffer syn = ByteBuffer.allocate(4);
                // ByteBuffer ack = ByteBuffer.allocate(4);
                syn.put(receivedPacket.getData(), 0, 4);
                // ack.put(receivedPacket.getData(), 4, 4);
                k++;
                if (waitingsyn == syn.getInt(0)) {
                    // kiem tra goi tin nhan thoa syn ko
                    waitingsyn = syn.getInt(0) + 1;
                    baos.write(receivedPacket.getData(), 8, 1016);
                    recieve += 1016;
                    acknum++;
                    // gui goi tin voi syn=0, ack=syn vua nhan
                    sendapacket(0, syn.getInt(0));
                } else {
                    System.out.println("Fail");
                    break;
                }
            }
            ByteBuffer syn = ByteBuffer.allocate(4);
            while (recieve < 524288) {
                // nhan 32 byte cuoi, tach ra de send goi ack 517
                DatagramPacket receivedPacket = new DatagramPacket(receivedata,
                        1024);
                ds.receive(receivedPacket);

                syn = ByteBuffer.allocate(4);
                syn.put(receivedPacket.getData(), 0, 4);
                //System.out.println(""syn.getInt(0) + "" + acknum);
                if (waitingsyn == syn.getInt(0)) {
                    waitingsyn = syn.getInt(0) + 1;
                    baos.write(receivedPacket.getData(), 8, 32);
                    recieve += 1016;
                    sendapacket(0, 517);
                }
            }
            FileOutputStream fos = new FileOutputStream("rsc//" + filename + "."
                    + numchunk + ".chunk");
            fos.write(baos.toByteArray());

            fos.flush();
            baos.close();
            fos.close();
            Chunkstat = 1;
            valid = false;
            String hashvalue = Hashcalc(filename + "."
                    + Integer.toString(numchunk) + ".chunk");
            String hashvalue2 = getHashChunk(filename, numchunk);
            if (hashvalue.equals(hashvalue2)) {
                System.out.println("checkhash ok");
                valid = true;
                //file nhan thanh cong
                Chunkstat = 1;

            }
            Thread t = new Thread(this);
            t.interrupt();
        } catch (Exception e) {
            ds.close();
            e.printStackTrace();
        }

    }

    private byte[] alterbuf(byte[] buff, int syn, int ack) {
        ByteBuffer bs = ByteBuffer.allocate(4);
        bs.putInt(syn);
        ByteBuffer ba = ByteBuffer.allocate(4);
        ba.putInt(ack);
        for (int i = 0; i < 4; i++) {
            buff[i] = bs.get(i);
        }
        for (int i = 4; i < 8; i++) {
            buff[i] = ba.get(i - 4);
        }
        return buff;
    }

    public int recieveapacket() throws IOException {
        while (true) {
            byte[] receivedata = new byte[1024];
            DatagramPacket receivedPacket = new DatagramPacket(receivedata, 1024);

            ds.receive(receivedPacket);
            if (receivedPacket.getPort() == secondport) {
                ByteBuffer syn = ByteBuffer.allocate(4);
                ByteBuffer ack = ByteBuffer.allocate(4);
                for (int i = 0; i < 4; i++) {
                    syn.put(receivedata.clone()[i]);
                    ack.put(receivedata.clone()[i + 4]);
                }
                return ack.getInt(0);
            }
        }
    }

    public void sendapacket(int syn, int ack) throws IOException {
        byte[] sentBuf = new byte[1024];
        alterbuf(sentBuf, syn, ack);
        DatagramPacket sentPacket = new DatagramPacket(sentBuf, sentBuf.length,
                host, secondport);
        ds.send(sentPacket);

    }

    private static String Hashcalc(String filename) {
        byte[] filebuf = new byte[524288];
        try {
            System.out.println(filename);
            FileInputStream fis = new FileInputStream("rsc//" + filename);
            fis.read(filebuf, 0, 524288);
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            md.update(filebuf, 0, 524288);
            byte[] mdbytes = md.digest();
            StringBuffer hexString = new StringBuffer();
            for (int i = 0; i < mdbytes.length; i++) {
                hexString.append(Integer.toHexString(0xFF & mdbytes[i]));
            }
            return hexString.toString();

        } catch (IOException | NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return "failed";
    }

    public static String getHashChunk(String filename, int chunk)
            throws IOException {
        String hash = null;
        File file = new File("rsc//" + filename + ".torrent");
        BufferedReader reader = new BufferedReader(new FileReader(file));

        String str = null;
        for (int i = 0; i < chunk + 2; i++) {
            str = reader.readLine();
        }
        hash = str;
        reader.close();
        return hash;
    }

    public static void stopthread() {
        t.interrupt();
    }
}
